package ahl;

import java.awt.Color;
import robocode.HitRobotEvent;
import robocode.HitWallEvent;
import robocode.Robot;
import robocode.ScannedRobotEvent;
import robocode.WinEvent;
import robocode.util.Utils;

/**
 * This is a competitive robot that will compete in the class tournament.
 * @author Arthur Lee
 */
public class BattleFire extends Robot {
  String enemyName;
  double firePower = 1.9;
  
  /**
   * The method that will run the robot.
   */
  public void run() {
    Color goldenYellow = new Color(255, 223, 0);
    setColors(Color.red, goldenYellow, Color.black);
    //Randomly rotates to the right and moves forward.
    while (true) {
      int turnRight = Utils.getRandom().nextInt(179);
      turnRight(turnRight);
      ahead(250);
      turnRadarRight(Double.POSITIVE_INFINITY);
    }
  }
  
  /**
   * Scans, targets, and aims for a robot. Uses arcsin and a few
   * guesses to aim for enemy robot. Strength of bullet is
   * perpendicular to distance between robots.
   * @param event The event in which an enemy is scanned by radar.
   */
  public void onScannedRobot(ScannedRobotEvent event) {
    //First scanned robot becomes tracked.
    if (enemyName == null) {
      enemyName = event.getName();
    }
    double enemyFieldAngle, aimAngle, relativeAngle;
    double enemyVelocity = event.getVelocity();
    double distance = event.getDistance();
    int turnRight;
    //Retrieves bullet strength based on distance.
    if (distance <= 150) {
      firePower = 2.9;
    }
    else if (distance > 150 && distance <= 450) {
      firePower = 1.9;
    }
    else {
      firePower = 0.9;
    }
    //Fire immediately without targeting measures.
    if (enemyVelocity <= 1.5) {
      enemyFieldAngle = getHeading() + event.getBearing();
      aimAngle = calculateAimAngle(enemyFieldAngle);
      turnGunRight(aimAngle);
      fire(firePower);
      turnRight = Utils.getRandom().nextInt(179);
      turnRight(turnRight);
      ahead(200);
      return;
    }
    //Retrieves angle to rotate in order to aim at enemy.
    enemyFieldAngle = getHeading() + event.getBearing();
    aimAngle = calculateAimAngle(enemyFieldAngle);
    double bulletSpeed = (20 - 3 * (firePower));
    //Finds the angle to rotate to fire bullet.
    double angle = Math.asin(enemyVelocity / bulletSpeed);
    angle = Math.toDegrees(angle);
    enemyFieldAngle = getHeading() + event.getBearing();
    double heading = event.getHeading();
    //Predicts the direction of the robot.
    if (enemyFieldAngle > 180 && enemyFieldAngle < 270) {
      if (heading >= enemyFieldAngle - 180 && heading <= enemyFieldAngle) {
        angle *= -1;
      }
    }
    else if (enemyFieldAngle > 0 && enemyFieldAngle < 90) {
      if (heading >= enemyFieldAngle + 180 && enemyFieldAngle >= heading) {
        angle *= -1;
      }
    }
    else if (enemyFieldAngle > 270 && enemyFieldAngle < 360) {
      if (heading > enemyFieldAngle - 180 && heading <= enemyFieldAngle ) {
        angle *= -1;
      }
    }
    else {
      if (heading < enemyFieldAngle + 180 && enemyFieldAngle > heading) {
        angle *= -1;
      }
    }
    //Turns right or left and shoots bullet.
    relativeAngle = getClosestAngle(aimAngle + angle);
    turnGunRight(relativeAngle);
    fire(firePower);
    turnRight = Utils.getRandom().nextInt(179);
    turnRight(turnRight);
    ahead(200);
  }
  
  /**
   * If enemy robot hits robot, turn and fire three in full power.
   * @param event The event which robot gets hit.
   */
  public void onHitRobot(HitRobotEvent event) {
    double enemyFieldAngle = getHeading() + event.getBearing();
    double aimAngle = calculateAimAngle(enemyFieldAngle);
    turnRight(aimAngle);
    fire(2.9);
    fire(2.9);
    fire(2.9);
  }
  
  /**
   * The robot's victory dance.
   * @param event The event which the robot wins.
   */
  public void onWin(WinEvent event) {
    int i = 0;
    while (true) {
      if (i > 50) {
        break;
      }
      turnLeft(360);
      turnRight(360);
      i++;
    }
  }
  
  /**
   * Calculates how far to turn right towards the enemy.
   * @param enemyFieldAngle Enemy's location on the field. 
   * @return Degrees to turn right to aim towards the robot.
   */
  public double calculateAimAngle(double enemyFieldAngle) {
    double travelAngle = enemyFieldAngle - getGunHeading();
    return getClosestAngle(travelAngle);
  }
  
  /**
   * Turns right 179 degrees and moves 100 pixels straight after
   * contact with the wall.
   * @param event The event when a robot hits the wall.
   */
  public void onHitWallEvent(HitWallEvent event) {
    turnRight(179);
    ahead(100);
  }
  
  /**
   * Finds the reflexive angle for a given angle.
   * @param fieldAngle The angle originally used to turn right.
   * @return The relative angle to turn towards.
   */
  public double getClosestAngle(double fieldAngle) {
    double closestAngle = fieldAngle;
    if (fieldAngle > 180) {
      closestAngle = fieldAngle - 360;
      return closestAngle;
    }
    if (fieldAngle < -180) {
      closestAngle = fieldAngle + 360;
      return closestAngle;
    }
    return closestAngle;
  }
}
